﻿#include "computevision.h"
#include<QDir>
#include<QLibrary>
#include<QPluginLoader>
#include<QFileDialog>
#include<QMessageBox>

ComputeVision::ComputeVision(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    populatePluginsMenu();

    ////显示图    
    ui.graphicsView->setScene(&scene);
    scene.addItem(&originalPixmap);
    scene.addItem(&processedPixmap);
    ui.graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);

    connect(ui.action_openImg, &QAction::triggered, this, &ComputeVision::slot_openImg);
}

ComputeVision::~ComputeVision()
{
}
/***************************************************************
 *  @brief     填充插件菜单、菜单项与dll路径关联、菜单项Triggered信号————ui显示槽函数
 *  @param     参数
 *  @note      备注
 *  @Sample usage:     函数的使用方法
 **************************************************************/
void ComputeVision::populatePluginsMenu()
{
    //载入所有插件，并填充菜单
    QDir pluginsDir(qApp->applicationDirPath());        //exe路径
    if (!pluginsDir.cd("plugins"))                      //若无法进入plugins文件夹则返回
    {
        return;
    }
    int counter = 0;    //统计有效插件，无则返回
    for(QString pluginName : pluginsDir.entryList(QDir::Files))   //遍历plugins中的插件（库）
    {
        if (QLibrary::isLibrary(pluginName))           //是否是库文件
        {
            QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(pluginName));    //加载插件
            if (Interface1 *plugin= qobject_cast<Interface1*>(pluginLoader.instance()))    //是否与插件接口兼容
            {
                counter++;
                //填充菜单
                QAction *pluginAction= ui.menu_plugins->addAction(plugin->title());
                //具体菜单项与dll路径关联(以后直接使用路径初始化具体的插件)
                pluginAction->setProperty("dllPath", pluginsDir.absoluteFilePath(pluginName)); //设置自定义的属性，及属性值（即每个菜单项对应一个dll路径）
                //菜单项Triggered信号————ui显示槽函数
                connect(pluginAction, &QAction::triggered, this, &ComputeVision::slot_pluginActionTriggered);
            }
        }
    }
    if (0 == counter)     //无有效插件则返回
    {
        return;
    }
}

/***************************************************************
 *  @brief     接收菜单项被点击信号的槽函数：初始化插件、显示ui、插件updateNeeded信号————槽函数
 *  @param     参数
 *  @note      备注
 *  @Sample usage:     函数的使用方法
 **************************************************************/
void ComputeVision::slot_pluginActionTriggered()
{

    if (currentPlugin !=nullptr)
    {
        delete currentPlugin;   //无需再delete currentPluginUi;因为这两个指针指向统一内存（即使类型不同）        
        currentPlugin = nullptr;
        currentPluginUi = nullptr;
    }
    
    //获得dll路径(即菜单项属性dllPath的值)
    QString currentPluginPath = QObject::sender()->property("dllPath").toString();
    //初始化插件
    QPluginLoader currentPluginLoader(currentPluginPath);
    currentPlugin = qobject_cast<Interface1*>(currentPluginLoader.instance());  //静态转换，QObject*转为Interface1*
    //显示ui
    currentPluginUi = qobject_cast<QWidget*> (currentPluginLoader.instance());
    ui.verticalLayout->addWidget(currentPluginUi);
    //插件updateNeeded信号————槽函数
    connect(currentPluginLoader.instance(), SIGNAL(updateNeeded()), this, SLOT(slot_currentPluginUpdateNeeded()));  //自定义的信号用旧方式SIGNAL
}

/***************************************************************
 *  @brief     接收插件updateNeeded信号的槽函数：处理图像、显示图像
 *  @param     参数
 *  @note      备注
 *  @Sample usage:     函数的使用方法
 **************************************************************/
//接收插件信号的槽函数
//初始化插件，调用插件里的图像处理函数
void ComputeVision::slot_currentPluginUpdateNeeded()
{
    //调用插件中的图像处理函数
    currentPlugin->processImage(originalMat, processedMat);
    //显示图像
    originalImg = QImage(originalMat.data, originalMat.cols, originalMat.rows, originalMat.step, QImage::Format_RGB888);
    processedImg = QImage(processedMat.data, processedMat.cols, processedMat.rows, processedMat.step, QImage::Format_RGB888);
    originalPixmap.setPixmap(QPixmap::fromImage(originalImg.rgbSwapped()));
    processedPixmap.setPixmap(QPixmap::fromImage(processedImg.rgbSwapped()));
}

void ComputeVision::slot_openImg()
{
    QString fileName = QFileDialog::getOpenFileName(this,
        tr("Open Input Image"),
        QDir::currentPath(),
        tr("Images") + " (*.jpg *.png *.bmp)");

    using namespace cv;
    originalMat = imread(fileName.toStdString());
    if (!originalMat.empty())
    {
        //slot_currentPluginUpdateNeeded();
        originalImg = QImage(originalMat.data, originalMat.cols, originalMat.rows, originalMat.step, QImage::Format_RGB888);
        originalPixmap.setPixmap(QPixmap::fromImage(originalImg.rgbSwapped()));
    }
    else if (!fileName.trimmed().isEmpty())
    {
        QMessageBox::critical(this,
            tr("Error"),
            tr("Make sure the image file exists "
                "and it is accessible!"));
    }
}